package edu.udel.mboch.towerdefense;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class TowerDefenseView extends View implements DialogInterface.OnClickListener
{
	public static Map<String, Bitmap> images;
	private TowerDefenseAndroidActivity activity;
	private Game game;
	private Paint paint;
	private TowerDefenseDatabase database;
	private boolean displayedResults;
	
	private Toast toast;
	private RectF basicTower;
	private RectF heavyTower;
	private RectF slowTower;
	private RectF splashTower;
	private RectF sellButton;
	private static Position pos = new Position(0, 0);
	private static Tower[] towerTypes = new Tower[]{new BasicTower(pos), new HeavyTower(pos), new SlowTower(pos), new SplashTower(pos)};
	
	private Tower chosenTower;
	private boolean sellMode;
	
	private int width;
	private int height;
	private float bottom;
	private float top;
	
	public TowerDefenseView(Context context, Game game, TowerDefenseDatabase database)
	{
		super(context);
		toast = Toast.makeText(getContext(), "", Toast.LENGTH_SHORT);
		activity = (TowerDefenseAndroidActivity)context;
		this.game = game;
		this.database = database;
		displayedResults = false;
		paint = new Paint();
		chosenTower = null;
		sellMode = false;
		try
		{
			loadImages();
		}
		catch(IOException e)
		{
			Log.i("TowerDefense", "Failed to load images");
		}
	}
	
	private void loadImages() throws IOException
	{
		images = new HashMap<String, Bitmap>();
		images.put("BasicMob", BitmapFactory.decodeStream(getContext().getAssets().open("BasicMob.png")));
		images.put("FastMob", BitmapFactory.decodeStream(getContext().getAssets().open("FastMob.png")));
		images.put("HeavyMob", BitmapFactory.decodeStream(getContext().getAssets().open("Monster2.png")));
		images.put("BossMob", BitmapFactory.decodeStream(getContext().getAssets().open("MONSTER.png")));
		images.put("BasicTower", BitmapFactory.decodeStream(getContext().getAssets().open("BasicTower.png")));
		images.put("HeavyTower", BitmapFactory.decodeStream(getContext().getAssets().open("HeavyTower.png")));
		images.put("SlowTower", BitmapFactory.decodeStream(getContext().getAssets().open("SlowTower.png")));
		images.put("SplashTower", BitmapFactory.decodeStream(getContext().getAssets().open("SplashTower.png")));
		images.put("Metal", BitmapFactory.decodeStream(getContext().getAssets().open("Metal.png")));
		images.put("Road", BitmapFactory.decodeStream(getContext().getAssets().open("Road.png")));
		images.put("Projectile", BitmapFactory.decodeStream(getContext().getAssets().open("Projectile.png")));
		images.put("SellButton", BitmapFactory.decodeStream(getContext().getAssets().open("SellButton.png")));
	}
	
	public Game getGame()
	{
		return game;
	}
	
	public void setGame(Game game)
	{
		this.game = game;
		displayedResults = false;
		invalidate();
	}
	
	protected void onDraw(Canvas canvas)
	{
		super.onDraw(canvas);
		if(game != null)
		{
			game.update();
			drawPieces(canvas);
			drawTowerChooser(canvas);
			drawInfoDisplay(canvas);
			if(game.isEnd() && !displayedResults)
			{
				displayedResults = true;
				AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
				alert.setTitle("Game over!");
				if(game.getWinner() == null)
					alert.setMessage("You Lost!");
				else
					alert.setMessage("Congratulations, you successfully fended off the monsters!");
				alert.setPositiveButton("Main Menu", this);
				alert.setCancelable(false);
				alert.show();
			}
			invalidate();
		}
	}
	
	public void drawTowerChooser(Canvas canvas)
	{
		Bitmap picture = null;
		float size = (float)width/towerTypes.length;
		paint.setColor(Color.DKGRAY);
		paint.setTextSize(size/10f);
		canvas.drawRect(new RectF(0, bottom, width, height), paint);
		paint.setColor(Color.argb(255, 0, 255, 0));
		for(int i = 0; i<towerTypes.length; i++)
		{
			RectF rect = new RectF(size*i, bottom, size*(i+1), height);
			if(towerTypes[i] instanceof BasicTower)
			{
				picture = images.get("BasicTower");
				basicTower = rect;
			}
			else if(towerTypes[i] instanceof HeavyTower)
			{
				picture = images.get("HeavyTower");
				heavyTower = rect;
			}
			else if(towerTypes[i] instanceof SlowTower)
			{
				picture = images.get("SlowTower");
				slowTower = rect;
			}
			else if(towerTypes[i] instanceof SplashTower)
			{
				picture = images.get("SplashTower");
				splashTower = rect;
			}
			if(i!=0)
				canvas.drawLine(size*i, bottom, size*i, height, paint);
			canvas.drawBitmap(picture, new Rect(0, 0, picture.getWidth(), picture.getHeight()), new RectF(size*i + size/4f, bottom, size*i + 3*size/4f, bottom + 2*(height-bottom)/5f), paint);
			canvas.drawText(towerTypes[i].getName(), size*i + size/5f, bottom + 24*(height-bottom)/48f, paint);
			canvas.drawText("Cost - $" + towerTypes[i].getCost(), size*i + size/5f, bottom + 29*(height-bottom)/48f, paint);
			canvas.drawText("Damage - " + towerTypes[i].getDamage(), size*i + size/5f, bottom + 34*(height-bottom)/48f, paint);
			canvas.drawText("Range - " + towerTypes[i].getRange(), size*i + size/5f, bottom + 39*(height-bottom)/48f, paint);
			String speed = 1000f/towerTypes[i].getSpeed() + "";
			if(speed.length() > 4)
				speed = speed.substring(0,4);
			canvas.drawText("Speed - " + speed, size*i + size/5f, bottom + 44*(height-bottom)/48f, paint);
		}
		invalidate();
	}
	
	private void drawInfoDisplay(Canvas canvas)
	{
		paint.setColor(Color.DKGRAY);
		canvas.drawRect(new RectF(0, 0, width, top), paint);
		paint.setColor(Color.argb(255, 0, 255, 0));
		paint.setTextSize(top/3f);
		Player player = game.getState().getPlayer();
		canvas.drawText("Cash", width/16f, top/3f, paint);
		canvas.drawText("$" + player.getCash(), width/16f, 5*top/6f, paint);
		canvas.drawText("Lives", 4*width/16f, top/3f, paint);
		canvas.drawText("" + player.getLives(), 4*width/16f, 5*top/6f, paint);
		canvas.drawText("Wave", 7*width/16f, top/3f, paint);
		canvas.drawText("" + game.getState().getWaves().getWaveNumber(), 7*width/16f, 5*top/6f, paint);
		paint.reset();
		sellButton = new RectF(12*width/16f, 0, 15*width/16f, top);
		Bitmap picture = images.get("SellButton");
		canvas.drawBitmap(picture, new Rect(0, 0, picture.getWidth(), picture.getHeight()), sellButton, paint);
	}
	
	private void drawPieces(Canvas canvas)
	{
		Grid grid = game.getState().getGrid();
		for(int i = 0; i<Grid.MAX_Y; i++)
			for(int j = 0; j<Grid.MAX_X; j++)
			{
				Bitmap picture = null;
				if(grid.getTowers()[i][j] != null)
				{
					if(grid.getTowers()[i][j] instanceof BasicTower)
						picture = images.get("BasicTower");
					else if(grid.getTowers()[i][j] instanceof HeavyTower)
						picture = images.get("HeavyTower");
					else if(grid.getTowers()[i][j] instanceof SlowTower)
						picture = images.get("SlowTower");
					else if(grid.getTowers()[i][j] instanceof SplashTower)
						picture = images.get("SplashTower");
				}
				else if(grid.getTerrain()[i][j] != null)
				{
					if(grid.getTerrain()[i][j] instanceof Metal)
						picture = images.get("Metal");
					else if(grid.getTerrain()[i][j] instanceof Road)
						picture = images.get("Road");
				}
				if(picture != null)
				{
					canvas.drawBitmap(picture, new Rect(0, 0, picture.getWidth(), picture.getHeight()), 
											new RectF((float)Math.ceil((double)width/Grid.MAX_X*j), (float)Math.ceil((double)(bottom-top)/Grid.MAX_Y*i)+top, 
											(float)Math.ceil((double)width/Grid.MAX_X*(j+1)), (float)Math.ceil((double)(bottom-top)/Grid.MAX_Y*(i+1))+top), paint);
				}
			}
		for(Mob m : grid.getMobs())
		{
			Bitmap picture = null;
			if(m instanceof BasicMob)
				picture = images.get("BasicMob");
			else if(m instanceof FastMob)
				picture = images.get("FastMob");
			else if(m instanceof HeavyMob)
				picture = images.get("HeavyMob");
			else if(m instanceof BossMob)
				picture = images.get("BossMob");
			if(picture != null)
			{
				if(m.isSlowed())
					paint.setColorFilter(new PorterDuffColorFilter(Color.argb(255, 175, 175, 255), PorterDuff.Mode.DARKEN));
				canvas.drawBitmap(picture, new Rect(0, 0, picture.getWidth(), picture.getHeight()), 
										new RectF((float)Math.ceil((double)width/Grid.MAX_X*m.getPosition().x()), (float)Math.ceil((double)(bottom-top)/Grid.MAX_Y*m.getPosition().y())+(bottom-top)/Grid.MAX_Y/9f+top, 
										(float)Math.ceil((double)width/Grid.MAX_X*(m.getPosition().x()+1)), (float)Math.ceil((double)(bottom-top)/Grid.MAX_Y*(m.getPosition().y()+1))+top), paint);
				if(m.isSlowed())
					paint.setColorFilter(null);
				paint.setColor(Color.argb(255, 255 - (int)(255*m.getHealth()/(double)m.getMaxHealth()), (int)(255*m.getHealth()/(double)m.getMaxHealth()), 0));
				canvas.drawRect(new RectF((float)Math.ceil((double)width/Grid.MAX_X*m.getPosition().x()),
										(float)Math.ceil((double)(bottom-top)/Grid.MAX_Y*m.getPosition().y())+top, 
										(float)Math.ceil((double)width/Grid.MAX_X*(m.getPosition().x()+1)) - (width/Grid.MAX_X - width/Grid.MAX_X*m.getHealth()/(float)m.getMaxHealth()),
										(float)Math.ceil((double)(bottom-top)/Grid.MAX_Y*(m.getPosition().y())) + (bottom-top)/Grid.MAX_Y/9f+top), paint);
			}
		}
		for(Projectile p : grid.getProjectiles())
		{
			Bitmap picture = images.get("Projectile");
			canvas.drawBitmap(picture, new Rect(0, 0, picture.getWidth(), picture.getHeight()),
								new RectF((float)(width/Grid.MAX_X*p.getPosition().x()), (float)((bottom-top)/Grid.MAX_Y*p.getPosition().y())+top,
											(float)(width/Grid.MAX_X*p.getPosition().x()) + 6, (float)((bottom-top)/Grid.MAX_Y*p.getPosition().y()) + 6 + top), paint);
		}
		
		Bitmap picture = null;
		if(chosenTower instanceof BasicTower)
			picture = images.get("BasicTower");
		else if(chosenTower instanceof HeavyTower)
			picture = images.get("HeavyTower");
		else if(chosenTower instanceof SlowTower)
			picture = images.get("SlowTower");
		else if(chosenTower instanceof SplashTower)
			picture = images.get("SplashTower");
		if(picture != null)
		{
			canvas.drawBitmap(picture, new Rect(0, 0, picture.getWidth(), picture.getHeight()), 
					new RectF((float)width/Grid.MAX_X*chosenTower.getPosition().x(), (float)(bottom-top)/Grid.MAX_Y*chosenTower.getPosition().y()+top, 
					(float)width/Grid.MAX_X*(chosenTower.getPosition().x()+1), (float)(bottom-top)/Grid.MAX_Y*(chosenTower.getPosition().y()+1)+top), paint);
			if(!grid.getTerrain()[chosenTower.getPosition().y()][chosenTower.getPosition().x()].isBuildable() || grid.getTowers()[chosenTower.getPosition().y()][chosenTower.getPosition().x()] != null)
				paint.setColor(Color.argb(150, 200, 0, 0));
			else
				paint.setColor(Color.argb(150, 0, 255, 0));
			for(Position p : chosenTower.positionsInRange())
			{
				if(!p.equals(chosenTower.getPosition()))
					canvas.drawRect(new RectF((float)width/Grid.MAX_X*p.x(), (float)(bottom-top)/Grid.MAX_Y*p.y()+top, 
							(float)width/Grid.MAX_X*(p.x()+1), (float)(bottom-top)/Grid.MAX_Y*(p.y()+1)+top), paint);
			}
			paint.reset();
		}
	}
	
	protected void onSizeChanged(int w, int h, int oldw, int oldh)
	{
		super.onSizeChanged(w, h, oldw, oldh);
		width = w;
		height = h;
		bottom = 4*height/5f;
		top = height/15f;
	}
	
	public boolean onTouchEvent(MotionEvent event)
	{
		int action = event.getAction();

		if (action == MotionEvent.ACTION_DOWN)
		{
			if (game != null && !game.isEnd())
			{
				if (game.getState().getPlayer() instanceof SingleHumanPlayer)
				{
					setHapticFeedbackEnabled(true);
					performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
					setHapticFeedbackEnabled(false);
					SingleHumanPlayer player = (SingleHumanPlayer)game.getState().getPlayer();
					String towerType = null;
					if(event.getY() < top)
					{
						if(sellButton.contains(event.getX(), event.getY()))
						{
							sellMode = true;
							toast.setText("Sell Mode");
							toast.show();
						}
					}
					else if(event.getY() > bottom)
					{
						sellMode = false;
						if(basicTower.contains(event.getX(), event.getY()))
						{
							towerType = "Basic";
						}
						else if (heavyTower.contains(event.getX(), event.getY()))
						{
							towerType = "Heavy";
						}
						else if(slowTower.contains(event.getX(), event.getY()))
						{
							towerType = "Slow";
						}
						else if(splashTower.contains(event.getX(), event.getY()))
						{
							towerType = "Splash";
						}
						if(towerType != null)
							player.handleSelection(towerType);
						towerType = player.getSelectionTowerType();
						if(towerType != null)
						{
							int row = (int)((event.getY()-top)/((bottom-top)/Grid.MAX_Y));
							if(row >= Grid.MAX_Y)
								row = Grid.MAX_Y-1;
							int col = (int)(event.getX()/(width/Grid.MAX_X));
							if(towerType.equals("Basic"))
								chosenTower = new BasicTower(new Position(col, row));
							else if(towerType.equals("Heavy"))
								chosenTower = new HeavyTower(new Position(col, row));
							else if(towerType.equals("Slow"))
								chosenTower = new SlowTower(new Position(col, row));
							else if(towerType.equals("Splash"))
								chosenTower = new SplashTower(new Position(col, row));
						}
					}
					else if(event.getY() < bottom && event.getY() > top)
					{
						((SingleHumanPlayer)game.getState().getPlayer()).clearTower();
						if(sellMode)
						{
							int col = (int)(event.getX(event.getPointerCount()-1)/(width/Grid.MAX_X));
							int row = (int)((event.getY(event.getPointerCount()-1)-top)/(((bottom-top)/Grid.MAX_Y)));
							if(row >= Grid.MAX_Y)
								row = Grid.MAX_Y-1;
							if(game.getState().getPlayer() instanceof SingleHumanPlayer)
								((SingleHumanPlayer)game.getState().getPlayer()).handleSell(row, col);
						}
					}
				}
			}
			return true;
		}
		else if(action == MotionEvent.ACTION_MOVE)
		{
			if(event.getY(event.getPointerCount()-1) > top)
			{
				int col = (int)(event.getX(event.getPointerCount()-1)/(width/Grid.MAX_X));
				int row = (int)((event.getY(event.getPointerCount()-1)-top)/(((bottom-top)/Grid.MAX_Y)));
				if(row >= Grid.MAX_Y)
					row = Grid.MAX_Y-1;
				if(chosenTower!=null)
				{
					chosenTower.getPosition().x(col);
					chosenTower.getPosition().y(row);
				}
			}
			return true;
		}
		else if (action == MotionEvent.ACTION_UP)
		{
			if (game != null && !game.isEnd())
			{
				if (game.getState().getPlayer() instanceof SingleHumanPlayer)
				{
					SingleHumanPlayer player = (SingleHumanPlayer)game.getState().getPlayer();
					float y = event.getY();
					if(y>bottom)
						player.handleSelection(null);
					if(y<bottom)
					{
						float x = event.getX();
						float squareHeight = (((bottom-top) * 1f) / Grid.MAX_Y);
						float squareWidth = ((width * 1f) / Grid.MAX_X);
						int row = (int)((y-top)/squareHeight);
						int col = (int)(x/squareWidth);
						player.handleSelection(row, col);
					}
					player.handleSell(-1, -1);
					chosenTower = null;
				}
			}
			if(game != null)
			{
				invalidate();
			}
		}
		return true;
	}

	public void onClick(DialogInterface dialog, int which)
	{
		Player player = game.getState().getPlayer();
		TowerDefenseGameRecord record = new TowerDefenseGameRecord(player.getName(), game.getState().getWaves().getWaveNumber(), player.getCash(), player.getLives(), System.currentTimeMillis());
		database.insertGameRecord(record);
		activity.openMenu();
		dialog.cancel();
	}
}
